#include <string>
#include <kvs/AVSField>
#include <kvs/ValueArray>
#include <kvs/Type>
#include <kvs/Vector3>
#include <kvs/PointObject>
#include <kvs/PointExporter>
#include <kvs/KVSMLObjectPoint>


void RegionGrowing(
    const kvs::ValueArray<kvs::UInt8>& values,
    const kvs::Vector3ui& dim,
    const kvs::Vector3ui& pos,
    const size_t id,
    kvs::ValueArray<kvs::UInt16>& ids,
    kvs::Vector3f& center,
    size_t& counter )
{
    const size_t index = pos.z() * dim.x() * dim.y() + pos.y() * dim.x() + pos.x();
    if ( index >= values.size() ) return;
    if ( ids[index] != 0 ) return;
    if ( values[index] == 0 ) return;

    ids[index] = id;
    center += kvs::Vector3f( pos.x(), pos.y(), pos.z() );
    counter++;

    RegionGrowing( values, dim, pos + kvs::Vector3ui(  1,  0,  0 ), id, ids, center, counter );
    RegionGrowing( values, dim, pos + kvs::Vector3ui(  0,  1,  0 ), id, ids, center, counter );
    RegionGrowing( values, dim, pos + kvs::Vector3ui(  0,  0,  1 ), id, ids, center, counter );
    RegionGrowing( values, dim, pos + kvs::Vector3ui( -1,  0,  0 ), id, ids, center, counter );
    RegionGrowing( values, dim, pos + kvs::Vector3ui(  0, -1,  0 ), id, ids, center, counter );
    RegionGrowing( values, dim, pos + kvs::Vector3ui(  0,  0, -1 ), id, ids, center, counter );
}

int main( int argc, char** argv )
{
    // Read input file.
    std::string filename( argv[1] );
    kvs::AVSField fld( filename );
    fld.print( std::cout );

    // Region growing and labeling.
    kvs::Vector3ui dim = fld.dim();
    kvs::ValueArray<kvs::UInt8> values = fld.values().asValueArray<kvs::UInt8>();
    kvs::ValueArray<kvs::UInt16> ids( values.size() ); ids.fill(0);
    size_t id = 1;
    std::vector<kvs::Vector3f> centers;
    for ( size_t z = 0, index = 0; z < dim.z(); z++ )
    {
        for ( size_t y = 0; y < dim.y(); y++ )
        {
            for ( size_t x = 0; x < dim.x(); x++, index++ )
            {
                if ( ids[index] == 0 && values[index] != 0 )
                {
                    kvs::Vector3ui pos( x, y, z );
                    kvs::Vector3f center = kvs::Vector3f::Zero();
                    size_t counter = 0;
                    RegionGrowing( values, dim, pos, id, ids, center, counter );
                    id++;
                    center /= static_cast<float>( counter );
                    centers.push_back( center );
                }
            }
        }
    }

    // Output center points as KVSML format data.
    kvs::ValueArray<kvs::Real32> coords( centers.size() * 3 );
    for ( size_t i = 0; i < centers.size(); i++ )
    {
        coords[ 3 * i + 0 ] = centers[i].x();
        coords[ 3 * i + 1 ] = centers[i].y();
        coords[ 3 * i + 2 ] = centers[i].z();
    }

    kvs::PointObject* object = new kvs::PointObject();
    object->setCoords( coords );
    object->setColor( kvs::RGBColor( 255, 0, 0 ) );
    object->setSize( 1 );
    object->print( std::cout << std::endl );

    kvs::KVSMLObjectPoint* kvsml = new kvs::PointExporter<kvs::KVSMLObjectPoint>( object );
    kvsml->write( "output.kvsml" );

    delete object;
    delete kvsml;

    return 0;
}
